package com.socodethis.spaceex;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.math.Rectangle;
import com.socodethis.spaceex.math.cPoint;
import com.socodethis.spaceex.math.cRect;

//This class creates them main map that the character will be navigating
//Also stores the current coordinates of the player
public class dungeonGenerator {
	//has to be nano for the random. milliseconds is too slow
	private Random random = new Random(System.nanoTime());
	
	//This is the map for the level stored in the dungeon class
	//TileHolder is a double array that holds TileClasses, or individual tiles
	//A TileClass has a floor by default, it can be also used to hold a structure
	//or a switch structure. The floor, structure, and switchStructure all
	//have properties defined in the spriteproperties class. For now the 
	//floor properties is the only class that is actually looked at, so it
	//is really the only thing that needs to be set
	TileHolder tHolder;

	private cPoint playerStart, playerLast, puzzleEntrance, puzzleExit;
	private ArrayList <buttonClass> buttons = new ArrayList <buttonClass>();
	private ArrayList <doorClass> doors = new ArrayList <doorClass>();
	private int index, width, height, numberOfWalls;
	private Color color;
	private int dungeonType,y,x,i;
	private boolean isPuzzle;
	private int[][] oMap;
	private cPoint randomPoint = new cPoint(0,0);
	private ArrayList<enemyClass> mapEnemies;
	
	public dungeonGenerator(dungeonGenerator dungeon){
		this(dungeon.index, dungeon.dungeonType);
	}
	//This function is used to generate fractal-like dungeons
	public void addPressureRoomToMap(cRect rect, cPoint exit, cPoint entrance){
		cPoint guess = new cPoint(entrance);
		//while(!returnPassable(guess) && (guess.getX() == exit.getX() && guess.getY() == exit.getY())){
		//	guess = new cPoint(rect.getRandomEdge());
		//}
		if(!returnDoor(guess)){
			makeGenericFloor(guess);
		}
		if(exit.getX() == rect.getPosition().getX() || exit.getX() == rect.getPosition().getX()+rect.getDimensions().getX()){
			addDoor(exit,new cPoint(0,0));
			makeDoor(exit);
		}else{
			addDoor(exit,new cPoint(0,0));
			makeDoorRotated(exit);
		}
		
		for(int y = (int) rect.getPosition().getY(); y <= (int) rect.getPosition().getY() + rect.getDimensions().getY();y++){
			for(int x = (int) rect.getPosition().getX(); x <= (int) rect.getPosition().getX() + rect.getDimensions().getX();x++){
				if(rect.onSquareBounds(new cPoint(x,y)) && !exit.cEquals(new cPoint(x,y)) && !guess.cEquals(new cPoint(x,y))){
					makeCliffWall(new cPoint(x,y));
					numberOfWalls++;
				}else if(!rect.onSquareBounds(new cPoint(x,y))){
					addButton(exit,new cPoint(x,y));
				}
			}
		}
		
		//Places 10 random stones in the puzzle
		/*int position;
		cPoint wallButton;
		for(int i = 0; i < 5; i++){
			position = random.nextInt(buttons.size()-1);
			wallButton = new cPoint(buttons.get(position).getButtonLocation());
			while((wallButton.getNextTo(exit) || wallButton.getNextTo(entrance))){
				position = random.nextInt(buttons.size()-1);
				wallButton = new cPoint(buttons.get(position).getButtonLocation());
			}
			//System.out.println(buttons.size());
			//wallButton.printPoint();
			buttons.remove(position);
			//System.out.println(buttons.size());
			makeCliffWall(wallButton);
			numberOfWalls++;
		}*/
		//System.out.println("Walls made");
		
		
		//Initializes all the buttons
		for(buttonClass button: buttons){
			button.setPressureSwitch(true);
			button.setFlippedOnOff(true);
			makePressureSwitch(button.getButtonLocation());
		}
		
		checkBox(false);
		
	}
	
	public void generateBoxPuzzleRoom(int index, int width, int height){
		this.index = index;
		this.width = width;
		this.height = height;
		int count = 0;
		int x,y;
		while(count < (width*height*.25)){
			x = random.nextInt( width );
			y = random.nextInt( height );
			if(!returnAnyProperties(new cPoint(x,y))){
				makeMovableBox(new cPoint(x,y));
				count++;
			}
		}
		count = 0;
		while(count < (width*height*.15)){
			x = random.nextInt( width );
			y = random.nextInt( height );
			if(!returnAnyProperties(new cPoint(x,y))){
				makeGenericWall(new cPoint(x,y));
				count++;
			}
		}
		numberOfWalls+=count;
	}
	
	public void generateHomeBase(int index, int width, int height){
		this.index = index;
		this.width = width;
		this.height = height;
		
		for(int y=45;y<46;y++){
			for(int x = 0; x< width; x++){
				makeCastleWall(new cPoint(x,y));
			}
		}
		for(int y=9;y<height;y++){
			for(int x = 24; x< 26; x++){
				makeRoad(new cPoint(x,y));
			}
		}
		for(int y=9;y<11;y++){
			for(int x = 0; x< width; x++){
				makeRoad(new cPoint(x,y));
			}
		}
		
		for(int y=27;y<29;y++){
			for(int x = 0; x< width; x++){
				makeRoad(new cPoint(x,y));
			}
		}
		
		ArrayList <cRect> houses = new ArrayList <cRect>();
		houses.add(new cRect(0,12, 22, 13));
		houses.add(new cRect(0,30, 22, 12));
		houses.add(new cRect(27,12, width-28, 13));
		houses.add(new cRect(27,30, width-28, 12));
		
		
		houses.add(new cRect(28,0, width-29, 7));
		houses.add(new cRect(0,0, 22, 7));
		
		for(cRect house:houses){
		for(int y=(int) house.getPosition().getY();y<(int) house.getPosition().getY()+(int) house.getDimensions().getY()+1;y++){
			for(int x = (int) house.getPosition().getX(); x< (int) house.getPosition().getX()+(int) house.getDimensions().getX()+1; x++){
				if(house.onSquareBounds(new cPoint(x,y))){
					makeTownWall(new cPoint(x,y));
				}else{
					makeDungeonFloor(new cPoint(x,y));
				}
			}
		}
		}
		checkBox(false);
		
		puzzleExit = new cPoint(25,49);
		//System.out.println("Here");
		puzzleEntrance = new cPoint(25,10);
		//System.out.println("Here");
		playerStart = new cPoint(puzzleEntrance);
		
	}
	
	public void generateAbandonedHomeBase(int index, int width, int height){
		this.index = index;
		this.width = width;
		this.height = height;
		
		for(int y=45;y<46;y++){
			for(int x = 0; x< width; x++){
				makeCastleWall(new cPoint(x,y));
			}
		}
		for(int y=9;y<height;y++){
			for(int x = 24; x< 26; x++){
				makeRoad(new cPoint(x,y));
			}
		}
		for(int y=9;y<11;y++){
			for(int x = 0; x< width; x++){
				makeRoad(new cPoint(x,y));
			}
		}
		
		for(int y=13;y<43;y++){
			for(int x = 0; x< 22; x++){
				makeTownWall(new cPoint(x,y));
			}
		}
		
		for(int y=13;y<43;y++){
			for(int x = 28; x< width; x++){
				makeTownWall(new cPoint(x,y));
			}
		}
		
		for(int y=0;y<9;y++){
			for(int x = 28; x< width; x++){
				makeTownWall(new cPoint(x,y));
			}
		}
		
		for(int y=0;y<9;y++){
			for(int x = 0; x< 22; x++){
				makeTownWall(new cPoint(x,y));
			}
		}
		
		for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				if(tHolder.anyProperties(new cPoint(x,y)) &&
						tHolder.anyProperties(new cPoint(x-1,y-1)) &&
						tHolder.anyProperties(new cPoint(x-1,y)) &&
						tHolder.anyProperties(new cPoint(x-1,y+1)) &&
						tHolder.anyProperties(new cPoint(x+1,y-1)) &&
						tHolder.anyProperties(new cPoint(x+1,y)) &&
						tHolder.anyProperties(new cPoint(x+1,y+1)) &&
						tHolder.anyProperties(new cPoint(x,y-1)) &&
						tHolder.anyProperties(new cPoint(x,y+1))){
					//Fill in the rectangles with dungeon tiles
					makeDungeonFloor(new cPoint(x,y));
				}
			}
		}
		
		createTerrain(new cPoint(25,25),4);
		//addHeight(new cPoint(0,0), .5f);
		
		checkBox(false);
		
	}
	
	public void generateVillageOffCenter(int index, int width, int height){
		//Alright, so this will be tricky. I will need to figure 
		//out how many squares can fit inside the map given to me first
		this.index = index;
		this.width = width;
		this.height = height;
		//This is the smallest they can be
		int dimensions = 3;
		while (((width * height)/10) > (dimensions  * dimensions)){
			dimensions++;
		}
		dimensions--;
		
		//Now the houses cannot be touching each other or the edges of the map
		ArrayList <cPoint> mapList = new ArrayList<cPoint>();
		for(int Y = 0; Y<height; Y++){
			for (int X=0; X<width; X++){
				mapList.add(new cPoint(X,Y));
			}
		}
		Collections.shuffle(mapList);
		for(cPoint point: mapList){
			if(point.getX() >0 && point.getY()>0 
					&& (point.getX() + dimensions) < width -1
					&& (point.getY() + dimensions) < height -1){
				if(!checkFloor(new cRect(point.getX()-1,point.getY()-1, dimensions + 3, dimensions + 3))){
					cRect house = new cRect(point.getX(),point.getY(), dimensions, dimensions);
					for(int y = (int) house.getPosition().getY()-1; y <= (int) house.getPosition().getY() + house.getDimensions().getY()+1;y++){
						for(int x = (int) house.getPosition().getX()-1; x <= (int) house.getPosition().getX() + house.getDimensions().getX()+1;x++){
							if(house.onSquareBounds(new cPoint(x,y))){
								makeCastleWall(new cPoint(x,y));
							}else if (house.inSquare(new cPoint(x,y))){
								makeDungeonFloor(new cPoint(x,y));
							}else{
								makeRoad(new cPoint(x,y));
							}
						}
					}
					makeDungeonFloor(house.getRandomEdge());
				}
			}
		}
		
	}
	
	public void generateMansionOffCenter(int index, int width, int height){
		//Alright, so this will be tricky. I will need to figure 
		//out how many squares can fit inside the map given to me first
		this.index = index;
		this.width = width;
		this.height = height;
		//Build at least this many houses
		int minNumberHouses = 5;
		//This is the smallest they can be
		int dimensions = 3;
		while (width * height > (dimensions  * dimensions) * minNumberHouses){
			dimensions++;
		}
		dimensions--;
		
		ArrayList <cRect> houses = new ArrayList<cRect>();
		//Now the houses cannot be touching each other or the edges of the map
		ArrayList <cPoint> mapList = new ArrayList<cPoint>();
		for(int Y = 0; Y<height; Y++){
			for (int X=0; X<width; X++){
				mapList.add(new cPoint(X,Y));
			}
		}
		Collections.shuffle(mapList);
		for(cPoint point: mapList){
			if(point.getX() >0 && point.getY()>0 
					&& (point.getX() + dimensions) < width -1
					&& (point.getY() + dimensions) < height -1){
				if(!checkFloor(new cRect(point.getX()-1,point.getY()-1, dimensions + 2, dimensions + 2))){
					houses.add(new cRect(point.getX(),point.getY(), dimensions, dimensions));
				}
			}
		}
		
		for(cRect house: houses){
			for(int y = (int) house.getPosition().getY(); y <= (int) house.getPosition().getY() + house.getDimensions().getY();y++){
				for(int x = (int) house.getPosition().getX(); x <= (int) house.getPosition().getX() + house.getDimensions().getX();x++){
					if(house.onSquareBounds(new cPoint(x,y))){
						if(     ((checkFloor(x-1,y) || house.onSquareBounds(new cPoint(x-1,y))) &&
								(checkFloor(x+1,y) || house.onSquareBounds(new cPoint(x+1,y))) &&
								(checkFloor(x,y-1) || house.onSquareBounds(new cPoint(x,y-1))) &&
								(checkFloor(x,y+1) || house.onSquareBounds(new cPoint(x,y+1))))){
							makeCastleWall(new cPoint(x,y));
						}
					}else{
						makeDungeonFloor(new cPoint(x,y));
					}
				}
			}
			
			//cPoint edge = new cPoint(house.getRandomEdge());
			//while(returnPassable(edge)){
			//	edge = new cPoint(house.getRandomEdge());
			//}
			//makeDungeonFloor(edge);
		}
		checkBox(false);
		//Fills in the center of the pond with water
		/*for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				if(returnAnyProperties(new cPoint(x,y)) &&
						returnAnyProperties(new cPoint(x-1,y-1)) &&
						returnAnyProperties(new cPoint(x-1,y)) &&
						returnAnyProperties(new cPoint(x-1,y+1)) &&
						returnAnyProperties(new cPoint(x+1,y-1)) &&
						returnAnyProperties(new cPoint(x+1,y)) &&
						returnAnyProperties(new cPoint(x+1,y+1)) &&
						returnAnyProperties(new cPoint(x,y-1)) &&
						returnAnyProperties(new cPoint(x,y+1))){
					makeDungeonFloor(new cPoint(x,y));
				}
			}
		}*/
		
		//for(cRect house: houses){
		//	makeDungeonFloor(house.getRandomEdge());
		//}
		
	}
	
	public void generateCliffRoom(int index, int width, int height){
		this.index = index;
		this.width = width;
		this.height = height;
		ArrayList <cPoint> builder = new ArrayList <cPoint>();
		builder.add(new cPoint(random.nextInt( width ),random.nextInt( height )));
		makeCliffWall(builder.get(0));
		numberOfWalls=1;
		Integer[] direction = new Integer[]{0, 1, 2, 3};
		
		//Builds the pond
		while(numberOfWalls < height*width*0.35 && !builder.isEmpty()){
			cPoint holder = new cPoint(builder.get(0));
			Collections.shuffle(Arrays.asList(direction));
			for(int road: direction){
				//Left
				if(road == 0 && holder.getX()!=0){
					if(!returnAnyProperties(new cPoint(holder.getX()-1, holder.getY()))){
						builder.add(new cPoint(holder.getX()-1, holder.getY()));
						makeCliffWall(new cPoint(holder.getX()-1, holder.getY()));
						numberOfWalls++;
					}
				}
				//Right
				if(road == 1 && holder.getX()!=width-1){
					if(!returnAnyProperties(new cPoint(holder.getX()+1, holder.getY()))){
						builder.add(new cPoint(holder.getX()+1, holder.getY()));
						makeCliffWall(new cPoint(holder.getX()+1, holder.getY()));
						numberOfWalls++;
					}
				}
				//Up
				if(road == 2 && holder.getY()!=0){
					if(!returnAnyProperties(new cPoint(holder.getX(), holder.getY()-1))){
						builder.add(new cPoint(holder.getX(), holder.getY()-1));
						makeCliffWall(new cPoint(holder.getX(), holder.getY()-1));
						numberOfWalls++;
					}
				}
				//Down
				if(road == 3 && holder.getY()!=height-1){
					if(!returnAnyProperties(new cPoint(holder.getX(), holder.getY()+1))){
						builder.add(new cPoint(holder.getX(), holder.getY()+1));
						makeCliffWall(new cPoint(holder.getX(), holder.getY()+1));
						numberOfWalls++;
					}
				}
			}
			builder.remove(0);
		}
		
		//Fills in the center of the pond with water
		for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				if(returnAnyProperties(new cPoint(x,y)) &&
						returnAnyProperties(new cPoint(x-1,y-1)) &&
						returnAnyProperties(new cPoint(x-1,y)) &&
						returnAnyProperties(new cPoint(x-1,y+1)) &&
						returnAnyProperties(new cPoint(x+1,y-1)) &&
						returnAnyProperties(new cPoint(x+1,y)) &&
						returnAnyProperties(new cPoint(x+1,y+1)) &&
						returnAnyProperties(new cPoint(x,y-1)) &&
						returnAnyProperties(new cPoint(x,y+1))){
					//makeGenericFloor(new cPoint(x,y));
					//Fill in the rectangles with dungeon tiles
					makeGenericWater(new cPoint(x,y));
				}
			}
		}
		
		
	}
	
	public void generateMountainRoom(int index, int width){
		this.index = index;
		this.width = width;
		this.height = width;
		puzzleExit = new cPoint(width/2,height/2);
		cRect boardRect = new cRect(4,4,this.width-8,this.height-8);
		cRect mountainRect = new cRect(puzzleExit.getX(),puzzleExit.getY(),1,1);
		while(boardRect.containsRect(mountainRect)){
			mountainRect.addWidth(2);
			mountainRect.addHeight(2);
			//System.out.println("Level" + width + " : "+height);
			//mountainRect.printDimensions();
			for(int y = (int) mountainRect.getPosition().getY(); y <= (int) mountainRect.getPosition().getY() + mountainRect.getDimensions().getY();y++){
				for(int x = (int) mountainRect.getPosition().getX(); x <= (int) mountainRect.getPosition().getX() + mountainRect.getDimensions().getX();x++){
					if(mountainRect.onSquareBounds(new cPoint(x,y))){
						makeCliffWall(new cPoint(x,y));
					}
				}
			}
			makeGenericFloor(mountainRect.getRandomEdge());
		}
		//mountainRect.printDimensions();
		
		mountainRect.addHeight(-4);
		mountainRect.addWidth(-4);
		
		//System.out.println(width + " : "+height);
		//mountainRect.printDimensions();
		
		puzzleExit = new cPoint(width/2,height/2);
		puzzleEntrance = new cPoint(getEmptySpaceExclusion(mountainRect));
		playerStart = new cPoint(puzzleEntrance);
		
	}
	
	public void generatePressurePlatePuzzleRoom(int index, int width, int height){
		int divisorLong = 0;
		cRect[] rects = new cRect[3];
		cPoint[] exits = new cPoint[3];
		cPoint[] entrances = new cPoint[3];
		cRect exitArea;
		cRect entranceArea;
		this.index = index;
		this.width = width;
		this.height = height;
		
		//This room builds 3 pressure plate rooms on top of each other. Each getting progressively harder
		//Uses a fractal-ish algorithm
		
		if(width > height){
			divisorLong = (width-3)/3;
			
			entranceArea = new cRect(0,0,1 + (3*divisorLong),height-1);
			exitArea = new cRect(divisorLong*2+divisorLong/2,0,width-divisorLong*2+divisorLong/2,height-1);
			
			rects[0] = new cRect(1,height/3,divisorLong,height/3);
			exits[0] = new cPoint(1 + divisorLong,random.nextInt( height/3-2)+height/3+1);
			entrances[0] = new cPoint(1,random.nextInt( height/3-2)+height/3+1);
			
			rects[1] = new cRect(1 + divisorLong,height/4,divisorLong,height/2);
			exits[1] = new cPoint(1 + (2*divisorLong),random.nextInt( height/2-2)+height/4+1);
			entrances[1] = new cPoint(exits[0]);
			
			rects[2] = new cRect(1 + (2*divisorLong),0,divisorLong,height-1);
			exits[2] = new cPoint(1 + (3*divisorLong),random.nextInt( height-2)+1);
			entrances[2] = new cPoint(exits[1]);
			
		}else{
			divisorLong = (height-3)/3;
			
			entranceArea = new cRect(0,0,width-2,1 + (3*divisorLong));
			exitArea = new cRect(0,divisorLong*2+divisorLong/2,width-1,height-divisorLong*2+divisorLong/2);
			
			rects[0] = new cRect(width/3,1,width/3,divisorLong);
			exits[0] = new cPoint(random.nextInt( width/3-2)+width/3+1,1 + divisorLong);
			entrances[0] = new cPoint(random.nextInt( width/3-2)+width/3+1,1);
			
			rects[1] = new cRect(width/4,1 + divisorLong,width/2,divisorLong);
			exits[1] = new cPoint(random.nextInt( width/2-2)+width/4+1,1 + (2*divisorLong));
			entrances[1] = new cPoint(exits[0]);
			
			rects[2] = new cRect(0,1 + (2*divisorLong),width-1,divisorLong);
			exits[2] = new cPoint(random.nextInt( width-2)+1,1 + (3*divisorLong));
			entrances[2] = new cPoint(exits[1]);
		}

		//System.out.println("Scene Dimensions: " + width + " : " + height);
		for(int i =0; i < rects.length;i++){
			//rects[i].printDimensions();
			addPressureRoomToMap(rects[i],exits[i],entrances[i]);
		}
		
		puzzleExit = new cPoint(getEmptySpace(exitArea));
		//System.out.println("Here");
		puzzleEntrance = new cPoint(getEmptySpace(entranceArea));
		//System.out.println("Here");
		playerStart = new cPoint(puzzleEntrance);
		//System.out.println("Here");
		
		/*int count = 0;
		int x,y;
		while(count < 10){
			x = random.nextInt( width );
			y = random.nextInt( height );
			if(!returnAnyProperties(new cPoint(x,y))){
				makeMovableBox(new cPoint(x,y));
				count++;
			}
		}*/
	}
	//A standard entrance to a castle/spaceship etc. It could be almost the exact same algo as the waterway room...
	public void generateEntranceRoom(int index, int width, int height, boolean entrance){
		this.index = index;
		this.width = width;
		this.height = height;
		
		cRect waterway = new cRect(0,0,0,0);
		cRect entranceArea = new cRect(0,0,0,0), exitArea = new cRect(0,0,0,0);
		ArrayList<cRect> bridges = new ArrayList<cRect>();
		int numBridges = 1;
		//getEmptySpace(cRect)
		//Now where to build the road...
		switch(random.nextInt( 2 )){
			// 0 = TopDown
			// 1 = LeftRight
			case 0: waterway = new cRect((float)random.nextInt( width-8 )+4,(float)0,(float)3,(float)height);
				for(int i = 0; i < numBridges; i++){
					bridges.add(new cRect(waterway.getPosition().getX(),random.nextInt(height-8)+4,(float)3,(float)3));
					entranceArea = new cRect(0,0,waterway.getPosition().getX()-1,height);
					exitArea = new cRect(waterway.getPosition().getX()+3,0,width - (waterway.getPosition().getX()+3),height);
				}
				break;
			case 1: waterway = new cRect((float)0,(float)random.nextInt( height-8 )+4,(float)width,(float)3);
				for(int i = 0; i < numBridges; i++){
					bridges.add(new cRect((float)random.nextInt(width-8)+4,waterway.getPosition().getY(),(float)3,(float)3));
					entranceArea = new cRect(0,0,width,waterway.getPosition().getY()-1);
					exitArea = new cRect(0,waterway.getPosition().getY()+3,width,height-(waterway.getPosition().getY()+3));
				}
				break;
		}
		for(int y = (int) waterway.getPosition().getY();y<waterway.getPosition().getY() + waterway.getDimensions().getY();y++){
			for(int x = (int) waterway.getPosition().getX();x<waterway.getPosition().getX() + waterway.getDimensions().getX();x++){
				makeCastleWall(new cPoint(x,y));
				numberOfWalls++;
			}
		}
		for(cRect rect: bridges){
			for(int y = (int) rect.getPosition().getY();y<rect.getPosition().getY() + rect.getDimensions().getY();y++){
				for(int x = (int) rect.getPosition().getX();x<rect.getPosition().getX() + rect.getDimensions().getX();x++){
					makeGenericFloor(new cPoint(x,y));
					tHolder.setMapFloor(new cPoint(x,y), "ice");
					numberOfWalls--;
				}
			}
		}
		
		for(int y = (int) exitArea.getPosition().getY(); y< exitArea.getPosition().getY()+exitArea.getDimensions().getY(); y++){
			for (int x = (int) exitArea.getPosition().getX(); x<exitArea.getPosition().getX()+exitArea.getDimensions().getX(); x++){
				makeGenericFloor(new cPoint(x,y));
				//Fill in the rectangles with dungeon tiles
				tHolder.setMapFloor(new cPoint(x,y), "dungeon");
			}
		}
		
		if(entrance){
			puzzleExit = new cPoint(getEmptySpace(exitArea));
			puzzleEntrance = new cPoint(getEmptySpace(entranceArea));
			playerStart = new cPoint(puzzleEntrance);
		}else{
			puzzleExit = new cPoint(getEmptySpace(entranceArea));
			puzzleEntrance = new cPoint(getEmptySpace(exitArea));
			playerStart = new cPoint(puzzleEntrance);
		}
		//System.out.println("Dungeon: " + index);
		//puzzleEntrance.printPoint();
		//puzzleExit.printPoint();
		//System.out.println();
	}
	
	public void generateWaterway(int index, int width, int height){
		this.index = index;
		this.width = width;
		this.height = height;
		cRect waterway = new cRect(0,0,0,0);
		ArrayList<cRect> bridges = new ArrayList<cRect>();
		int numBridges = 1;
		//Now where to build the road...
		switch(random.nextInt( 2 )){
			// 0 = TopDown
			// 1 = LeftRight
			case 0: waterway = new cRect((float)random.nextInt( width-8 )+4,(float)0,(float)3,(float)height);
				for(int i = 0; i < numBridges; i++){
					bridges.add(new cRect(waterway.getPosition().getX(),(float)random.nextInt(height-2)+1,(float)3,(float)1));
				}
				break;
			case 1: waterway = new cRect((float)0,(float)random.nextInt( height-8 )+4,(float)width,(float)3);
				for(int i = 0; i < numBridges; i++){
					bridges.add(new cRect((float)random.nextInt(width-2)+1,waterway.getPosition().getY(),(float)1,(float)3));
				}
				break;
		}
		for(int y = (int) waterway.getPosition().getY();y<waterway.getPosition().getY() + waterway.getDimensions().getY();y++){
			for(int x = (int) waterway.getPosition().getX();x<waterway.getPosition().getX() + waterway.getDimensions().getX();x++){
				makeGenericWater(new cPoint(x,y));
				numberOfWalls++;
			}
		}
		for(cRect rect: bridges){
			for(int y = (int) rect.getPosition().getY();y<rect.getPosition().getY() + rect.getDimensions().getY();y++){
				for(int x = (int) rect.getPosition().getX();x<rect.getPosition().getX() + rect.getDimensions().getX();x++){
					makeBridge(new cPoint(x,y));
					numberOfWalls--;
				}
			}
		}
		
		int trees = random.nextInt( 10 )+10;
		int count = 0;
		int x,y;
		boolean onBridge;
		while(count < trees){
			onBridge = false;
			x = random.nextInt( width );y = random.nextInt( height );
			for(cRect rect: bridges){
				if(rect.inSquare(new cPoint(x,y))||waterway.inSquare(new cPoint(x,y))){
					onBridge = true;
				}
			}
			if(!onBridge){
				makeGenericTree(new cPoint(x,y));
			}
			count++;
		}
		numberOfWalls+=trees;
		
	}
	//By far the easiest dungeon to make
	public void generateRoadways(int index, int width, int height){
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		//This ensures that the character does not start out on the edges of the map
		//map = new int [width][height];				
		//Make everything a floor
		//for(int y = 0; y< height; y++){
		//	for (int x=0; x<width; x++){
		//		this.map[x][y]= 1;
		//	}
		//}
		cRect road = new cRect(0,0,0,0);
		//Now where to build the road...
		switch(random.nextInt( 2 )){
			// 0 = TopDown
			// 1 = LeftRight
			case 0: road = new cRect((float)random.nextInt( width-8 )+4,(float)0,(float)3,(float)height);break;
			case 1: road = new cRect((float)0,(float)random.nextInt( height-8 )+4,(float)width,(float)3);break;
		}
		for(int y = (int) road.getPosition().getY();y<road.getPosition().getY() + road.getDimensions().getY();y++){
			for(int x = (int) road.getPosition().getX();x<road.getPosition().getX() + road.getDimensions().getX();x++){
				makeRoad(new cPoint(x,y));
			}
		}
		int trees = random.nextInt( 10 )+10;
		int count = 0;
		int x,y;
		while(count < trees){
			x = random.nextInt( width );y = random.nextInt( height );
			if(!road.inSquare(new cPoint(x,y))){
				makeGenericTree(new cPoint(x,y));
			}
			count++;
		}
		numberOfWalls=trees;
	}
	//Be very careful with the puzzle rooms. They can have multiple entrances, but only one exit. Like your mom
	public void generateButtonPuzzleRoom(int index, int width, int height){
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		//This ensures that the character does not start out on the edges of the map
		//Created custom class so that I could tweek the contains function
		ArrayList <cRect> burst = new ArrayList<cRect>();
		//There should be at least 4 chambers
		int numBoxes = 6;
								
		//Make everything a floor
		//for(int y = 0; y< height; y++){
		//	for (int x=0; x<width; x++){
		//		this.map[x][y]= 1;
		//	}
		//}
		boolean touched = false;
		cRect dungeon = new cRect(-1,-1,width+1,height+1);
		for(int count = 0;count < numBoxes;count++){
			//Randomly generate the squares
			int selectorX = random.nextInt( width );
			int selectorY = random.nextInt( height );
			//The length of the burst
			int rectWidth = random.nextInt( (int) Math.floor(width/10) )+3;
			int rectHeight = random.nextInt( (int) Math.floor(height/10) )+3;
			for(cRect rect:burst){
				if(rect.overlaps(new cRect(selectorX-1,selectorY-1,rectWidth+1,rectHeight+1))){
					touched = true;
				}
			}
			if(!touched && dungeon.containsRect(new cRect(selectorX,selectorY,rectWidth,rectHeight))){
				burst.add(new cRect(selectorX,selectorY,rectWidth,rectHeight));
			}else{
				count--;
			}
			touched = false;
		}
		//System.out.println("After Expand");
		for(cRect rect:burst){
			//Draw the outlines of the rectangle
			for(float y = rect.getPosition().getY(); y<= rect.getPosition().getY()+rect.getDimensions().getY(); y++){
				if(dungeon.withinSquare(new cPoint(rect.getPosition().getX(),y))){
					int x = (int) rect.getPosition().getX();
					makeGenericWall(new cPoint(x,y));
				}
				if(dungeon.withinSquare(new cPoint((rect.getPosition().getX()+rect.getDimensions().getX()),y))){
					int x = (int) (rect.getPosition().getX()+rect.getDimensions().getX());
					makeGenericWall(new cPoint(x,y));
				}
			}
			//Draw the outlines of the rectangle
			for(float x = rect.getPosition().getX(); x<= rect.getPosition().getX()+rect.getDimensions().getX(); x++){
				if(dungeon.withinSquare(new cPoint(x,rect.getPosition().getY()))){
					int y = (int) rect.getPosition().getY();
					makeGenericWall(new cPoint(x,y));
				}
			if(dungeon.withinSquare(new cPoint(x,(rect.getPosition().getY()+rect.getDimensions().getY())))){
					int y = (int)(rect.getPosition().getY()+rect.getDimensions().getY());
					makeGenericWall(new cPoint(x,y));
				}
			}
			
			//These next four if statements draw the lines
			//Have to put in a check for double lines to make sure that the puzzle can be made and solved 
			
			if(rect.getPosition().getY()!=0){
				//dungeon.printDimensions();
				//rect.printDimensions();
				for(float y = rect.getPosition().getY()-1,x = (float) (rect.getPosition().getX()+rect.getDimensions().getX()/2);
						y>=0 && returnPassable(new cPoint(x,y)); y--){
						if(testDoubleWall(new cPoint(x,y),new cPoint(1,0))){
							makeGenericWall(new cPoint(x,y));
						}else{
							break;
						}
				}
			}
			if(rect.getPosition().getY()!=height-1){
				for(float y = rect.getPosition().getY()+rect.getDimensions().getY()+1,x = (float) (rect.getPosition().getX()+rect.getDimensions().getX()/2);
						y<height && returnPassable(new cPoint(x,y)); y++){
					if(testDoubleWall(new cPoint(x,y),new cPoint(1,0))){
						makeGenericWall(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
					
			if(rect.getPosition().getX()!=0){
				//dungeon.printDimensions();
				//rect.printDimensions();
				for(float x = rect.getPosition().getX()-1,y = (float) (rect.getPosition().getY()+rect.getDimensions().getY()/2);
						x>=0 && returnPassable(new cPoint(x,y)); x--){
					if(testDoubleWall(new cPoint(x,y),new cPoint(0,1))){
						makeGenericWall(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
			if(rect.getPosition().getX()!=width-1){
				for(float x = rect.getPosition().getX()+rect.getDimensions().getX()+1,y = (float) (rect.getPosition().getY()+rect.getDimensions().getY()/2);
						x<width && returnPassable(new cPoint(x,y)); x++){
					if(testDoubleWall(new cPoint(x,y),new cPoint(0,1))){
						makeGenericWall(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
		}
		puzzleEntrance = getEmptySpace();		
		//puzzleExit.printPoint();
		playerStart = new cPoint(puzzleEntrance);
		//Make sure that each box is accessible
		checkBox(true);
		SolvableClass puzzleSolver = new SolvableClass(getSolvableMap(),new cPoint(width,height),puzzleEntrance);
		puzzleExit = new cPoint(puzzleSolver.getExit());
		for(int i =0; i<puzzleSolver.getButtonSize();i++){
			addButton(puzzleSolver.getButtonIndex(i).getDoor(),puzzleSolver.getButtonIndex(i).getButtonLocation());
			addDoor(puzzleSolver.getButtonIndex(i).getDoor(),puzzleSolver.getButtonIndex(i).getButtonLocation());
			makeButton(new cPoint( puzzleSolver.getButtonIndex(i).getButtonLocation().getX(),
					puzzleSolver.getButtonIndex(i).getButtonLocation().getY()));
			
		}
		//addDoor(new cPoint(x-1,y),addButton(new cPoint(x-1,y)));
		//playerStart.printPoint();
		numberOfWalls =0;
		for(int y = 0; y< height; y++){
			for (int x = 0; x<width; x++){
				if(returnPassable(new cPoint(x,y))){
					numberOfWalls++;
				}
			}
		}
		//printFloorMap();
	}
	//This function is used to generate squareFence dungeons
	public void generateSquareFenceRoom(int index, int width, int height){
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		//This ensures that the character does not start out on the edges of the map
		//map = new int [width][height];
		//Created custom class so that I could tweek the contains function
		ArrayList <cRect> burst = new ArrayList<cRect>();
		//There should be at least 4 chambers
		int numBoxes = 3;
						
		//Make everything a wall
		//for(int y = 0; y< height; y++){
		//	for (int x=0; x<width; x++){
		//		this.map[x][y]= 1;
		//	}
		//}
		boolean touched = false;
		cRect dungeon = new cRect(-1,-1,width+1,height+1);
		for(int count = 0;count < numBoxes;count++){
			//Randomly generate the squares
			int selectorX = random.nextInt( width );
			int selectorY = random.nextInt( height );
			//The length of the burst
			int rectWidth = random.nextInt( (int) Math.floor(width/10) )+3;
			int rectHeight = random.nextInt( (int) Math.floor(height/10) )+3;
			for(cRect rect:burst){
				if(rect.overlaps(new cRect(selectorX-1,selectorY-1,rectWidth+1,rectHeight+1))){
					touched = true;
				}
			}
			if(!touched && dungeon.containsRect(new cRect(selectorX,selectorY,rectWidth,rectHeight))){
				burst.add(new cRect(selectorX,selectorY,rectWidth,rectHeight));
			}else{
				count--;
			}
			touched = false;
		}
		//System.out.println("After Expand");
		for(cRect rect:burst){
			//Draw the outlines of the rectangle
			for(float y = rect.getPosition().getY(); y<= rect.getPosition().getY()+rect.getDimensions().getY(); y++){
				if(dungeon.withinSquare(new cPoint(rect.getPosition().getX(),y))){
					int x = (int) rect.getPosition().getX();
					makeGenericWall(new cPoint(x,y));
				}
				if(dungeon.withinSquare(new cPoint((rect.getPosition().getX()+rect.getDimensions().getX()),y))){
					int x = (int) (rect.getPosition().getX()+rect.getDimensions().getX());
					makeGenericWall(new cPoint(x,y));
				}
			}
			//Draw the outlines of the rectangle
			for(float x = rect.getPosition().getX(); x<= rect.getPosition().getX()+rect.getDimensions().getX(); x++){
				if(dungeon.withinSquare(new cPoint(x,rect.getPosition().getY()))){
					int y = (int) rect.getPosition().getY();
					makeGenericWall(new cPoint(x,y));
				}
			if(dungeon.withinSquare(new cPoint(x,(rect.getPosition().getY()+rect.getDimensions().getY())))){
					int y = (int)(rect.getPosition().getY()+rect.getDimensions().getY());
					makeGenericWall(new cPoint(x,y));
				}
			}
			
			//These next four if statements draw the lines
			//Have to put in a check for double lines to make sure that the puzzle can be made and solved 
			
			if(rect.getPosition().getY()!=0){
				//dungeon.printDimensions();
				//rect.printDimensions();
				for(float y = rect.getPosition().getY()-1,x = (float) (rect.getPosition().getX()+rect.getDimensions().getX()/2);
						y>=0 && returnPassable(new cPoint(x,y)); y--){
						if(testDoubleWall(new cPoint(x,y),new cPoint(1,0))){
							makeGenericTree(new cPoint(x,y));
						}else{
							break;
						}
				}
			}
			if(rect.getPosition().getY()!=height-1){
				for(float y = rect.getPosition().getY()+rect.getDimensions().getY()+1,x = (float) (rect.getPosition().getX()+rect.getDimensions().getX()/2);
						y<height && returnPassable(new cPoint(x,y)); y++){
					if(testDoubleWall(new cPoint(x,y),new cPoint(1,0))){
						makeGenericTree(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
					
			if(rect.getPosition().getX()!=0){
				//dungeon.printDimensions();
				//rect.printDimensions();
				for(float x = rect.getPosition().getX()-1,y = (float) (rect.getPosition().getY()+rect.getDimensions().getY()/2);
						x>=0 && returnPassable(new cPoint(x,y)); x--){
					if(testDoubleWall(new cPoint(x,y),new cPoint(0,1))){
						makeGenericTree(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
			if(rect.getPosition().getX()!=width-1){
				for(float x = rect.getPosition().getX()+rect.getDimensions().getX()+1,y = (float) (rect.getPosition().getY()+rect.getDimensions().getY()/2);
						x<width && returnPassable(new cPoint(x,y)); x++){
					if(testDoubleWall(new cPoint(x,y),new cPoint(0,1))){
						makeGenericTree(new cPoint(x,y));
					}else{
						break;
					}
				}
			}
		}
		//Make sure that each box is accessible
		checkBox(false);
		numberOfWalls =0;
		for(int y = 0; y< height; y++){
			for (int x = 0; x<width; x++){
				if(!returnPassable(new cPoint(x,y))){
					numberOfWalls++;
				}
			}
		}
	}
	//This function is used to generate chamber dungeons
	//Picks an n number of points(squares) in the rooms, and expands
	//them until the entire room is covered in squares. Then repeats the 
	//overroom algo for connections
	public void generateChamberRoom(int index, int width, int height){
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		//This ensures that the character does not start out on the edges of the map
		//map = new int [width][height];
		//Created custom class so that I could tweek the contains function
		ArrayList <cRect> rectangles = new ArrayList<cRect>();
		//There should be at least 5 chambers
		int numBoxes = random.nextInt( 20 )+10;
				
		//Make everything a floor
		//for(int y = 0; y< height; y++){
		//	for (int x=0; x<width; x++){
		//		this.map[x][y]= 1;
		//	}
		//}
		
		for(int count = 0;count < numBoxes;count++){
			//Randomly generate the rectangles
			int selectorX = random.nextInt( width );
			int selectorY = random.nextInt( height );
			int rectWidth = 1;
			int rectHeight = 1;
			rectangles.add(new cRect(selectorX,selectorY,rectWidth,rectHeight));
		}
		
		//Now we want to randomly generate an n amount of boxes. We will then check each tile to make sure that
		//it is not in any of the boxes. 
		boolean intersectW,intersectH,expanded = true;
		cRect testRectW,testRectH;
		cRect dungeon = new cRect(0,0,width,height);
		//System.out.println("Before Expand");
		//Expand the rectangles
		while(expanded){
		expanded = false;
		//For each rectangle, look at if there is still space to expand
		for(int i = 0; i < rectangles.size();i++){
			testRectW = new cRect(rectangles.get(i));
			testRectH = new cRect(rectangles.get(i));
			testRectW.addWidth(1);
			testRectH.addHeight(1);
			intersectW = false;
			intersectH = false;
			for(int j = 0; j < rectangles.size();j++){
				//If you are not evaluating the same rectangle, 
				//and you haven't intersected anything
				if(i!=j && !intersectW){
					if(testRectW.overlaps(rectangles.get(j))){
						intersectW = true;
					}
				}
				if(i!=j && !intersectH){
					if(testRectH.overlaps(rectangles.get(j))){
						intersectH = true;
					}
				}
			}
			switch(random.nextInt(2)){
			case 0:
				if(!intersectH && dungeon.containsRect(testRectH)&& testRectH.getPosition().getY()>0 
						&& (testRectH.getDimensions().getY() + testRectH.getPosition().getY())<height-1){
					//rectangles.get(i).printDimensions();
					rectangles.get(i).addHeight(1);
					//rectangles.get(i).printDimensions();
					expanded = true;
				}
				else if(!intersectW && dungeon.containsRect(testRectW) && testRectW.getPosition().getX()>0 
						&& (testRectW.getDimensions().getX() + testRectW.getPosition().getX())<width-1){
					//rectangles.get(i).printDimensions();
					rectangles.get(i).addWidth(1);
					//rectangles.get(i).printDimensions();
					expanded = true;
				}
			break;
			case 1:
				switch(random.nextInt(2)){
				case 0:
				if(!intersectH && dungeon.containsRect(testRectH)&& testRectH.getPosition().getY()>0 
						&& (testRectH.getDimensions().getY() + testRectH.getPosition().getY())<height-1){
					//rectangles.get(i).printDimensions();
					rectangles.get(i).addHeight(1);
					//rectangles.get(i).printDimensions();
					expanded = true;
				}
				break;
				case 1:
				if(!intersectW && dungeon.containsRect(testRectW) && testRectW.getPosition().getX()>0 
						&& (testRectW.getDimensions().getX() + testRectW.getPosition().getX())<width-1){
					//rectangles.get(i).printDimensions();
					rectangles.get(i).addWidth(1);
					//rectangles.get(i).printDimensions();
					expanded = true;
				}
				break;
				}
			break;
			}
		}
		}
		dungeon = new cRect(-1,-1,width+1,height+1);
		//System.out.println("After Expand");
		for(cRect rect:rectangles){
			for(float y = rect.getPosition().getY(); y<= rect.getPosition().getY()+rect.getDimensions().getY(); y++){
				if(dungeon.withinSquare(new cPoint(rect.getPosition().getX(),y))){
					makeGenericWall(new cPoint(rect.getPosition().getX(),y));
				}
				if(dungeon.withinSquare(new cPoint((rect.getPosition().getX()+rect.getDimensions().getX()),y))){
					makeGenericWall(new cPoint((rect.getPosition().getX()+rect.getDimensions().getX()),y));
				}
			}
			for(float x = rect.getPosition().getX(); x<= rect.getPosition().getX()+rect.getDimensions().getX(); x++){
				if(dungeon.withinSquare(new cPoint(x,rect.getPosition().getY()))){
					makeGenericWall(new cPoint(x,rect.getPosition().getY()));
				}
				if(dungeon.withinSquare(new cPoint(x,(rect.getPosition().getY()+rect.getDimensions().getY())))){
					makeGenericWall(new cPoint(x,(rect.getPosition().getY()+rect.getDimensions().getY())));
				}
			}
		}
		
		//Now we turn all the walls that are completely contained
				//in other walls into floors
		for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				if(!returnPassable(new cPoint(x,y)) &&
						!returnPassable(new cPoint(x-1,y-1)) &&
						!returnPassable(new cPoint(x-1,y)) &&
						!returnPassable(new cPoint(x-1,y+1)) &&
						!returnPassable(new cPoint(x+1,y-1)) &&
						!returnPassable(new cPoint(x+1,y)) &&
						!returnPassable(new cPoint(x+1,y+1)) &&
						!returnPassable(new cPoint(x,y-1)) &&
						!returnPassable(new cPoint(x,y+1))){
					makeGenericWall(new cPoint(x,y));
				}
			}
		}
		
		/*for(float y = 0; y< height; y++){
			this.map[0][(int) y]= 0;
			this.map[width-1][(int) y]= 0;
		}
		for(float x = 0; x< width; x++){
			this.map[(int) x][0]= 0;
			this.map[(int) x][height-1]= 0;
		}*/
		
		//Finally, We need to make a path through the boxes so the every part of the dungeon is accessible from every other part
		//Find every instance of a wall being in between two floors. If it is impossible to reach the other floor, then eliminate the wall
		//Theoretically, this check should be very comp intensive
		checkBox(false);
		//we smooth out the design by completing the corners
		//for(int z = 0; z < numBoxes; z++){
		for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				int count = 0;
				if(!returnPassable(new cPoint(x,y+1))){count++;}
				if(!returnPassable(new cPoint(x,y-1))){count++;}
				if(!returnPassable(new cPoint(x-1,y))){count++;}
				if(!returnPassable(new cPoint(x+1,y))){count++;}
				if (count == 3){
					makeGenericTree(new cPoint(x,y));
				}
			}
		}
		numberOfWalls =0;
		for(int y = 0; y< height; y++){
			for (int x = 0; x<width; x++){
				if(!returnPassable(new cPoint(x,y))){
					numberOfWalls++;
				}
			}
		}
		//}numberOfWalls
	}
	//This function is used to generate overlapping rooms
	//Made by generating a set of n rectangles within a given world,
	//and deleting the parts where they overlap. Easiest room to make.
	//Designed like so because it looks cool. Is computationally difficult to render
	public void generateOverRoom(int index, int width, int height){
		int[][] holderMap;
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		numberOfWalls =0;
		//This ensures that the character does not start out on the edges of the map
		//map = new int [width][height];
		holderMap = new int [width][height];
		//Created custom class so that I could tweek the contains function
		ArrayList <cRect> rectangles = new ArrayList<cRect>();
		//There should be at least two boxes
		int numBoxes = random.nextInt( 10 )+2;
				
		//Make everything a wall
		for(int y = 0; y< height; y++){
			for (int x=0; x<width; x++){
				makeCastleWall(new cPoint(x,y));
			}
		}
		for(int count = 0;count < numBoxes;count++){
			//Randomly generate the rectangles
			int selectorX = random.nextInt( width );
			int selectorY = random.nextInt( height );
			//Squares must be at least 3x3
			int rectWidth = random.nextInt( width-selectorX )+3;
			int rectHeight = random.nextInt( height-selectorY )+3;
			rectangles.add(new cRect(selectorX,selectorY,rectWidth,rectHeight));
		}
		
		//Now we want to randomly generate an n amount of boxes. We will then check each tile to make sure that
		//it is not in any of the boxes. 
		boolean noIntersect;
		for(int y = 0; y< height; y++){
			for (int x=0; x<width; x++){
				noIntersect = true;
				for(cRect rect:rectangles){
					if(rect.inSquare(new cPoint(x,y))){
						noIntersect = false;
					}
				}
				if (noIntersect){
					makeGenericFloor(new cPoint(x,y));
					holderMap[x][y] =1;
				}else{
					holderMap[x][y] =0;
				}
			}
		}
		//Now we turn all the walls that are completely contained
		//in other walls into floors
		for(int y = 1; y< height-1; y++){
			for (int x = 1; x<width-1; x++){
				if(holderMap[x][y] == 0 &&
						holderMap[x-1][y-1] == 0 &&
						holderMap[x-1][y] == 0 &&
						holderMap[x-1][y+1] == 0 &&
						holderMap[x+1][y-1] == 0 &&
						holderMap[x+1][y] == 0 &&
						holderMap[x+1][y+1] == 0 &&
						holderMap[x][y-1] == 0 &&
						holderMap[x][y+1] == 0){
					makeGenericFloor(new cPoint(x,y));
					//Fill in the rectangles with dungeon tiles
					tHolder.setMapFloor(new cPoint(x,y), "dungeon");
				}
			}
		}
		
		//Finally, we need to make a path through the boxes so the every part of the dungeon is accessable from every other part
		//Find every instance of a wall being in between two floors. If it is impossible to reach the other floor, then eliminate the wall
		checkBox(false);
		numberOfWalls =0;
		for(int y = 0; y< height; y++){
			for (int x = 0; x<width; x++){
				if(!returnPassable(new cPoint(x,y))){
					numberOfWalls++;
				}
			}
		}
	}
	//This function is used to generate maze-like dungeons
	//Generated using a modified version of kruskal's algorithm. Easiest to render
	public void generateMaze(int index, int width, int height, boolean waterway){
		//Defines a random color for the map to distinguish it from other maps in the world
		this.index = index;
		this.width = width;
		this.height = height;
		numberOfWalls =0;
		//This ensures that the character does not start out on the edges of the map
		playerStart = new cPoint(random.nextInt( width-2 )+1,random.nextInt( height-2 )+1);
		//map = new int [width][height];
		int plot;
		List<cPoint> trail = new ArrayList<cPoint>();
		Integer[] direction = new Integer[]{0, 1, 2, 3};
		cPoint holder;
		
		for(int y = 0; y< height; y++){
			for (int x=0; x<width; x++){
				if(!waterway){
					makeGenericTree(new cPoint(x,y));
				}else{
					makeGenericWater(new cPoint(x,y));
				}
			}
		}
				
		//This is the point where the player starts
				
		trail.add(new cPoint(playerStart));
				
		//Uses kruskal's algorithm to generate a random navigable map
		while (!trail.isEmpty()){
			//Picks a random wall to branch the trail out at
			plot = random.nextInt( trail.size() );
			holder = new cPoint(trail.get(plot));
			//this.map[(int) holder.getX()][(int) holder.getY()]= 1;
			if(!waterway){
				makeGenericFloor(new cPoint(holder.getX(),holder.getY()));
			}else{
				makeBridge(new cPoint(holder.getX(),holder.getY()));
			}
			// Shuffle the elements in the array
			//This is to make sure that the roads twist, and
			//are not straight corridors after generation
			Collections.shuffle(Arrays.asList(direction));
			//If this direction is in the map
			for (int road : direction){
				if (road == 0){
					if (holder.getX()-1 != 0)
					{
						//If the next cell over in the same direction is not in the maze
						if (checkWall(holder.getX()-2, holder.getY())){
							//Mark the cell in between as a transition, and the next cell as part of maze 
							//this.map[(int) (holder.getX()-1)][(int) holder.getY()]= 1;
							//this.map[(int) (holder.getX()-2)][(int) holder.getY()]= 1;
							if(!waterway){
								makeGenericFloor(new cPoint(holder.getX()-1,holder.getY()));
								makeGenericFloor(new cPoint(holder.getX()-2,holder.getY()));
							}else{
								makeBridge(new cPoint(holder.getX()-1,holder.getY()));
								makeBridge(new cPoint(holder.getX()-2,holder.getY()));
							}
							trail.add(new cPoint(holder.getX()-2, holder.getY()));
						}
					}
				}
				if (road == 1){
					if (holder.getY()+1 != height-1)
					{
						if (checkWall(holder.getX(), holder.getY()+2)){
							//this.map[(int) holder.getX()][(int) (holder.getY()+1)]= 1;
							//this.map[(int) holder.getX()][(int) (holder.getY()+2)]= 1;
							if(!waterway){
								makeGenericFloor(new cPoint(holder.getX(),holder.getY()+1));
								makeGenericFloor(new cPoint(holder.getX(),holder.getY()+2));
							}else{
								makeBridge(new cPoint(holder.getX(),holder.getY()+1));
								makeBridge(new cPoint(holder.getX(),holder.getY()+2));
							}
							trail.add(new cPoint(holder.getX(), holder.getY()+2));
						}
					}
				}
				if (road == 2){
					if (holder.getX()+1 != width-1)
					{
						if (checkWall(holder.getX()+2, holder.getY())){
							//this.map[(int) (holder.getX()+1)][(int) holder.getY()]= 1;
							//this.map[(int) (holder.getX()+2)][(int) holder.getY()]= 1;
							if(!waterway){
								makeGenericFloor(new cPoint(holder.getX()+1,holder.getY()));
								makeGenericFloor(new cPoint(holder.getX()+2,holder.getY()));
							}else{
								makeBridge(new cPoint(holder.getX()+1,holder.getY()));
								makeBridge(new cPoint(holder.getX()+2,holder.getY()));
							}
							trail.add(new cPoint(holder.getX()+2, holder.getY()));
						}
					}
				}
				if (road == 3){
					if (holder.getY()-1 != 0)
					{
						if (checkWall(holder.getX(), holder.getY()-2)){
							//this.map[(int) holder.getX()][(int) (holder.getY()-1)]= 1;
							//this.map[(int) holder.getX()][(int) (holder.getY()-2)]= 1;
							if(!waterway){
								makeGenericFloor(new cPoint(holder.getX(),holder.getY()-1));
								makeGenericFloor(new cPoint(holder.getX(),holder.getY()-2));
							}else{
								makeBridge(new cPoint(holder.getX(),holder.getY()-1));
								makeBridge(new cPoint(holder.getX(),holder.getY()-2));
							}
							trail.add(new cPoint(holder.getX(), holder.getY()-2));
						}
					}
				}
			}
			trail.remove(plot);
					
		}
		/*if(waterway){
			int x,y,count=0;
			while(count < (width*height*.05)){
				x = random.nextInt( width );
				y = random.nextInt( height );
				if(returnAnyProperties(new cPoint(x,y))){
					makeWoodenPole(new cPoint(x,y));
					count++;
				}
			}
		}*/
				
				//
		//map[(int) (playerStart.getX()-1)][(int) (playerStart.getY()-1)] = 1;
		//map[(int) (playerStart.getX())][(int) (playerStart.getY()-1)] = 1;
		//map[(int) (playerStart.getX()+1)][(int) (playerStart.getY()-1)] = 1;
		//map[(int) (playerStart.getX()-1)][(int) (playerStart.getY())] = 1;
		//map[(int) (playerStart.getX()+1)][(int) (playerStart.getY())] = 1;
		//map[(int) (playerStart.getX()-1)][(int) (playerStart.getY()+1)] = 1;
		//map[(int) (playerStart.getX())][(int) (playerStart.getY()+1)] = 1;
		//map[(int) (playerStart.getX()+1)][(int) (playerStart.getY()+1)] = 1;
	}
	public dungeonGenerator(int index, int dungeonType){
		
		//int dungeonType = random.nextInt( 9 );
		//int dungeonType = 5;
		mapEnemies = new ArrayList<enemyClass>();
		this.dungeonType = dungeonType;
		int mapHeight = random.nextInt( 20 )+15;
		int mapWidth = random.nextInt( 20 )+15;
		tHolder = new TileHolder();
		tHolder.buildMap(new cPoint(mapWidth,mapHeight));
		this.color = new Color();
		//this.color.set(.01f*(float)random.nextInt(100), .01f*(float)random.nextInt(100), .01f*(float)random.nextInt(100), 1);
		this.color.set(1,1,1,1);
		playerLast = new cPoint(-1,-1);
		isPuzzle = false;
		puzzleEntrance = new cPoint(0,0);
		puzzleExit = new cPoint(0,0);
		numberOfWalls = 0;
		switch(dungeonType){
			case 0:
				while(numberOfWalls<(mapWidth*mapHeight)/8){
					generateButtonPuzzleRoom(index, mapWidth, mapHeight);
				}
				isPuzzle = true;
				//A pleyerStart is defined in this dungeon, so it shouldn't be set afterwards
				//playerStart = new cPoint(getEmptySpace());
				break;
			case 1:
				while(numberOfWalls<(mapWidth*mapHeight)/8){
					generateSquareFenceRoom(index, mapWidth, mapHeight);
				}
				playerStart = new cPoint(getEmptySpace());
				break;
			case 2:
				//This way, only the best maps are added to the world
				//Does slow down the comp
				while(numberOfWalls<(mapWidth*mapHeight)/4){
					generateChamberRoom(index, mapWidth, mapHeight);
				}
				playerStart = new cPoint(getEmptySpace());
				break;
				//This algo naturally selects less walls
			case 3:
				generateMaze(index, mapWidth, mapHeight, false);
				//this.makeBare(.05f);
				//this.makeBare(getDungeonType(random.nextInt( 10 )));
				break;
			case 4:
				while(numberOfWalls<(mapWidth*mapHeight)/10){
					generateOverRoom(index, mapWidth, mapHeight);
				}
				playerStart = new cPoint(getEmptySpace());
				break;
			case 5:
				generateRoadways(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 6:
				generateWaterway(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 7:
				generatePressurePlatePuzzleRoom(index, mapWidth, mapHeight);
				isPuzzle = true;
				break;
			case 8: 
				generateBoxPuzzleRoom(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 9: 
				//This is an entrance from a castle
				generateEntranceRoom(index, mapWidth, mapHeight, true);
				isPuzzle = true;
				break;
			case 10:
				//This is an exit from a castle
				generateEntranceRoom(index, mapWidth, mapHeight, false);
				isPuzzle = true;
				break;
			case 11:
				//This is an exit from a castle
				generateCliffRoom(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 12:
				//This is an exit from a castle
				//The map needs to be built again, because this room is square
				tHolder.buildMap(new cPoint(mapWidth,mapWidth));
				generateMountainRoom(index, mapWidth);
				isPuzzle = true;
				break;
			case 13:
				generateMaze(index, mapWidth, mapHeight, true);
				//this.makeBare(.05f);
				//this.makeBare(getDungeonType(random.nextInt( 10 )));
				break;
			case 14:
				generateMansionOffCenter(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 15:
				generateVillageOffCenter(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			case 16:
				mapWidth = 50;
				mapHeight = 50;
				tHolder.buildMap(new cPoint(mapWidth,mapHeight));
				generateHomeBase(index, mapWidth, mapHeight);
				isPuzzle = true;
				break;
			case 17:
				mapWidth = 50;
				mapHeight = 50;
				tHolder.buildMap(new cPoint(mapWidth,mapHeight));
				generateAbandonedHomeBase(index, mapWidth, mapHeight);
				playerStart = new cPoint(getEmptySpace());
				break;
			default:generateRoadways(index, mapWidth, mapHeight);
			playerStart = new cPoint(getEmptySpace());
			break;
		}
	}
	public float getDungeonType(int seed){
		switch(seed){
			//This is a full dungeon
			case 0: //System.out.println("full dungeon");
			return .05f;
			//Half dungeon. Castle or something
			case 1: //System.out.println("Half dungeon");
			return .10f;
			//Thick forest
			case 2: //System.out.println("Thick forest");
			return .15f;
			//Normal forest
			case 3: //System.out.println("Normal forest");
			return .20f;
			//Bare forest
			case 4: //System.out.println("Bare forest");
			return .25f;
			//Desert
			case 5: //System.out.println("Desert");
			return .30f;
			//Ruins
			case 6: //System.out.println("Ruins");
			return .35f;
			//Plains
			case 7: //System.out.println("Plains");
			return .40f;
			//Fighting Grounds
			case 8: //System.out.println("Fighting Grounds");
			return .45f;
			//Happy Valley
			case 9: //System.out.println("Happy Valley");
			return .50f;
			//Dungeon seed is obviously the fastest, so that is the default
			default:return .5f;
		}
	}
	//Destroys an X percent of the dungeon's walls
	public void makeBare(float percent){
		float walls = 0;
		for(int y = 0; y < height;y++){
			for(int x  =0 ;x< width;x++){
				if (!returnPassable(new cPoint(x,y))){
					walls++;
				}
			}
		}
		walls *= percent;
		//System.out.println(walls);
		int count=0;
		while(count<walls){
			//The switcher takes the point and moves in the designated axis and direction until
			//a wall is found. Just taking a random point slowed down the comp too much. If nothing is found,
			//another guess is made
			int switcherAxis = random.nextInt( 2 );
			int switcherDirection = random.nextInt( 2 );
			int selectorX = random.nextInt( width-2 )+1;
			int selectorY = random.nextInt( height-2 )+1;
			
			//X axis
			if(switcherAxis == 0){
				//Negative
				if(switcherDirection == 0){
					while(!checkWall(selectorX,selectorY) || selectorX >=0){
						selectorX--;
					}
					if(checkWall(selectorX,selectorY)){
						makeGenericFloor(new cPoint(selectorX,selectorX));
						count++;
					}
				}
				//Positive
				else{
					while(!checkWall(selectorX,selectorY) || selectorX <width){
						selectorX++;
					}
					if(checkWall(selectorX,selectorY)){
						makeGenericFloor(new cPoint(selectorX,selectorX));
						count++;
					}
				}
			}
			//Y axis
			else{
				//Negative
				if(switcherDirection == 0){
					while(!checkWall(selectorX,selectorY) || selectorY >=0){
						selectorY--;
					}
					if(checkWall(selectorX,selectorY)){
						makeGenericFloor(new cPoint(selectorX,selectorX));
						count++;
					}
				}
				//Positive
				else{
					while(!checkWall(selectorX,selectorY) || selectorY <height){
						selectorY++;
					}
					if(checkWall(selectorX,selectorY)){
						makeGenericFloor(new cPoint(selectorX,selectorX));
						count++;
					}
				}
			}
			
		}
	}
	
	//This is where the enemies are stored. Since we want the bad guys to be localized to
	//each dungeon, they need to be stored here. Making anything but shallow copies of this arraylist
	//will dramatically slow down the program
	public void addEnemy(enemyClass enemy){
		mapEnemies.add(enemy);
	}
	
	public ArrayList<enemyClass> getEnemies(){
		return mapEnemies;
	}
	
	public void clearEnemies(){
		mapEnemies.clear();
	}
	
	private void resetProperties(cPoint position){
		tHolder.setMapStructure(position, "null");
		tHolder.setMapSwitchStructure(position, "null");
		for(int i = 0; i < tHolder.getPropSize();i++){
			tHolder.setPropertyFloor(position, i, false);
		}
	}
	
	private int[][] returnPathMap(){
		int[][] map = new int[width][height];
		for(int y = 0; y< height;y++){
			for(int x = 0;x<width;x++){
				if(returnPassable(new cPoint (x,y))){
					map[x][y]=1;
				}else{
					map[x][y]=0;
				}
			}
		}
		return map;
	}
	
	public void setTiles(boolean rotateDoors){
		Sprite sprite;
		cPoint origin = new cPoint(-.1f,.3f);
		cPoint structSize = new cPoint(1.3142135f,2.5f);
		//float rotation=133;
		for(int y = 0; y < height; y++) {
			for(int x = 0; x < width; x++) {
				sprite = tHolder.getFloor(new cPoint(x,y)).getSprite();
				sprite.setColor(getColor());
				sprite.rotate90(false);
				sprite.setSize(1, 1);
				//sprite.setPosition(x,y);
				tHolder.getFloor(new cPoint(x,y)).setSprite(sprite);

				tHolder.setMapDirt(new cPoint(x,y),"dirt");
				sprite = tHolder.getDirt(new cPoint(x,y)).getSprite();
				sprite.setOrigin(origin.getX(), origin.getY());
				sprite.setSize((float) structSize.getX(), (float) structSize.getY());
				tHolder.getDirt(new cPoint(x,y)).setSprite(sprite);
				
				if(tHolder.getStructure(new cPoint(x,y)).getName().indexOf("null")==-1){
					sprite = tHolder.getStructure(new cPoint(x,y)).getSprite();
					sprite.setOrigin(origin.getX(), origin.getY());
					//sprite.setRotation(rotation);
					sprite.setSize((float) structSize.getX(), (float) structSize.getY());
					//sprite.setPosition((float) (x+1.5),y);
					//if(tHolder.getTile(new cPoint(x,y)).floorHasProperty(4) && rotateDoors){
					//	sprite.flip(true, false);
					//}
					tHolder.getStructure(new cPoint(x,y)).setSprite(sprite);
				}
				if(tHolder.getSwitchStructure(new cPoint(x,y)).getName().indexOf("null")==-1){
					sprite = tHolder.getSwitchStructure(new cPoint(x,y)).getSprite();
					sprite.setOrigin(origin.getX(), origin.getY());
					//sprite.setRotation(rotation);
					sprite.setSize((float) structSize.getX(), (float) structSize.getY());
					//sprite.setPosition((float) (x+1.5),y);
					//if(tHolder.getTile(new cPoint(x,y)).floorHasProperty(4) && rotateDoors){
					//	sprite.flip(true, false);
					//}
					tHolder.getSwitchStructure(new cPoint(x,y)).setSprite(sprite);
				}
			}
		}
	}
	
	public void switchSwitchPics(cPoint pos){
		tHolder.switchTile(pos);
	}
	
	private void makeGenericWall(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "test");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeGenericWater(cPoint position){
		tHolder.setMapFloor(position, "water");
		resetProperties(position);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeCastleWall(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "castle");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeTownWall(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "town");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeCliffWall(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "cliff");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeGenericTree(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "tree");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makeGenericFloor(cPoint position){
		tHolder.setMapFloor(position, tHolder.getDefaultFloor());
		resetProperties(position);
	}
	
	private void makeBridge(cPoint position){
		tHolder.setMapFloor(position, "wood");
		resetProperties(position);
		//tHolder.setMapFloor(position, "wood");
	}
	
	private void makeRoad(cPoint position){
		tHolder.setMapFloor(position, "road");
		resetProperties(position);
		//tHolder.setMapFloor(position, "wood");
	}
	
	private void makeDungeonFloor(cPoint position){
		tHolder.setMapFloor(position, "dungeon");
		resetProperties(position);
		//tHolder.setMapFloor(position, "wood");
	}
	
	private void makeGenericExit(cPoint position){
		//Gdx.app.log("Placed","---------------");
		//position.printPoint();
		resetProperties(position);
		tHolder.setMapStructure(position, "teleport");
		tHolder.setPropertyStructure(position, 1, true);
		tHolder.setPropertyFloor(position, 1, true);
		tHolder.setPropertySwitchStructure(position, 1, true);
	}
	
	private void makeButton(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "buttonOff");
		tHolder.setMapSwitchStructure(position, "buttonOn");
		tHolder.setPropertyStructure(position, 2, true);
		tHolder.setPropertySwitchStructure(position, 2, true);
		tHolder.setPropertyFloor(position, 2, true);
	}
	private void makeWoodenPole(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "woodenpole");
		tHolder.setPropertyStructure(position, 0, true);
		tHolder.setPropertyFloor(position, 0, true);
	}
	
	private void makePressureSwitch(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "PlateOff");
		tHolder.setMapSwitchStructure(position, "PlateOn");
		tHolder.setPropertyStructure(position, 2, true);
		tHolder.setPropertySwitchStructure(position, 2, true);
		tHolder.setPropertyFloor(position, 2, true);
	}
	
	private void makeDoor(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "doorC");
		tHolder.setMapSwitchStructure(position, "doorO");
		tHolder.setPropertyStructure(position, 3, true);
		tHolder.setPropertySwitchStructure(position, 3, true);
		tHolder.setPropertyFloor(position, 3, true);
	}
	
	private void makeDoorRotated(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "doorC");
		tHolder.setMapSwitchStructure(position, "doorO");
		tHolder.setPropertyStructure(position, 4, true);
		tHolder.setPropertySwitchStructure(position, 4, true);
		tHolder.setPropertyFloor(position, 4, true);
	}
	
	private void makeMovableBox(cPoint position){
		resetProperties(position);
		tHolder.setMapStructure(position, "box");
		tHolder.setPropertyStructure(position, 5, true);
		tHolder.setPropertyFloor(position, 5, true);
	}
	
	public void addHeight(cPoint location, float height){
		tHolder.getFloor(location).setHeight(height);
	}
	
	public TileClass getFloorProperties(cPoint position){
		return tHolder.getTile(position);
	}
	public boolean returnPassable(cPoint position){
		return !tHolder.getFloor(position).getPropAtIndex(0);
	}
	public boolean returnExit(cPoint position){
		return tHolder.getFloor(position).getPropAtIndex(1);
	}
	public boolean returnButton(cPoint position){
		return tHolder.getFloor(position).getPropAtIndex(2);
	}
	public boolean returnDoor(cPoint position){
		return tHolder.getFloor(position).getPropAtIndex(3) 
				|| tHolder.getFloor(position).getPropAtIndex(4);
	}
	public boolean returnBox(cPoint position){
		return tHolder.getFloor(position).getPropAtIndex(5); 
	}
	public boolean returnAnyProperties(cPoint position){
		return tHolder.getFloor(position).anyProperties();
	}
	private cPoint getExitRandomEdges(){
		//This determines if the exit will be located on the X or Y axis
		int XorY = random.nextInt( 2 );
		//Near or far side of that axis
		int NorF = random.nextInt( 2 );
		//Standard selectors
		int selectorX = random.nextInt( width-2 );
		int selectorY = random.nextInt( height-2 );
		//X axis
		if(XorY == 0){
			//Near Side
			if(NorF == 0){return new cPoint(selectorX+1,selectorY);}
			//Far Side
			else{return new cPoint(selectorX+1,height-1);}
		}
		//Y axis
		else{
			//Near Side
			if(NorF == 0){return new cPoint(0,selectorY+1);}
			//Far Side
			else{return new cPoint(width-1,selectorY+1);}
		}
	}
	public cPoint getExitRandom(){
		int selectorX = random.nextInt( width-2 );
		int selectorY = random.nextInt( height-2 );
		return new cPoint(selectorX,selectorY);
	}
	//There needs to be an added check here to see if the exit is reachable
	public cPoint createExit(boolean exit){
		cPoint position;
		if(!isPuzzle){
			//Set the proposed exit
			position = new cPoint(getExitRandom());
			//While the exit doesn't land on another exit...
			while(returnAnyProperties(new cPoint(position.getX(),position.getY()))){
				//Keep guessing
				position = new cPoint(getExitRandom());
			}
			//Gdx.app.log("Exit","---------------");
			//position.printPoint();
			//If found return
			//map[(int) position.getX()][(int) position.getY()] = -1;
			makeGenericExit(new cPoint(position.getX(),position.getY()));
		}
		else{
			if(exit){
				//map[(int) puzzleExit.getX()][(int) puzzleExit.getY()] = -1;
				makeGenericExit(new cPoint(puzzleExit.getX(),puzzleExit.getY()));
				position = new cPoint(puzzleExit);
			}
			//Entrance
			else{
				//map[(int) playerStart.getX()][(int) playerStart.getY()] = -1;
				makeGenericExit(new cPoint(playerStart.getX(),playerStart.getY()));
				position = new cPoint(playerStart);
			}
		}
		return position;
	}
	public boolean checkWall(float X, float Y){
		if ((X >= 0) && (Y >= 0) && (X<width) && (Y<height)){
			if (!returnPassable(new cPoint(X,Y))){
			//The next cell over is not a path nor outside of the map
				return true;
			}
		}
		return false;
	}
	public boolean checkFloor(float X, float Y){
		if ((X >= 0) && (Y >= 0) && (X<width) && (Y<height)){
			if (!returnAnyProperties(new cPoint(X,Y))){
				return true;
			}
		}
		return false;
	}

	public boolean checkFloor(cRect rect){
		for(y = (int) rect.getPosition().getY(); y < rect.getPosition().getY() + rect.getDimensions().getY();y++){
			for(x = (int) rect.getPosition().getX(); x < rect.getPosition().getX() + rect.getDimensions().getX();x++){
				if(returnAnyProperties(new cPoint(x,y))){
					return true;
				}
			}
		}
		return false;
	}
	
	public void checkBox(boolean buttonPuzzle){
		ArrayList <cPoint> mapList = new ArrayList<cPoint>();
		for(y = 0; y<height; y++){
			for (x=0; x<width; x++){
				if (checkFloor(x,y)){
					mapList.add(new cPoint(x,y));
				}
			}
		}
		Collections.shuffle(mapList);
		Integer[] direction = new Integer[]{0, 1, 2, 3};
		shortestPath pathFinder;
		for(i = 0; i < mapList.size();i++){
			x = (int) mapList.get(i).getX();
			y = (int) mapList.get(i).getY();
				//Shuffle the directions
				Collections.shuffle(Arrays.asList(direction));
				for(int wayCheck:direction){
				switch(wayCheck){
				case 0:
				if(checkWall(x-1,y) && checkFloor(x-2,y)){
					pathFinder = new shortestPath(returnPathMap(),new cPoint(x,y), new cPoint(x-2,y),width,height);
					//pathFinder.setNewPath(new cPoint(x,y), new cPoint(x-2,y));
					if(pathFinder.returnPath().size()<2){
						makeGenericFloor(new cPoint(x-1,y));
						if(buttonPuzzle){
							makeDoor(new cPoint(x-1,y));
						}
					}
				}
				break;
				case 1:
				if(checkWall(x+1,y) && checkFloor(x+2,y)){
					//pathFinder.setNewPath(new cPoint(x,y), new cPoint(x+2,y));
					pathFinder = new shortestPath(returnPathMap(),new cPoint(x,y), new cPoint(x+2,y),width,height);
					if(pathFinder.returnPath().size()<2){
						makeGenericFloor(new cPoint(x+1,y));
						if(buttonPuzzle){
							makeDoor(new cPoint(x+1,y));
						}
					}
				}
				break;
				case 2:
				if(checkWall(x,y-1) && checkFloor(x,y-2)){
					//pathFinder.setNewPath(new cPoint(x,y), new cPoint(x,y-2));
					pathFinder = new shortestPath(returnPathMap(),new cPoint(x,y), new cPoint(x,y-2),width,height);
					if(pathFinder.returnPath().size()<2){
						makeGenericFloor(new cPoint(x,y-1));
						if(buttonPuzzle){
							makeDoorRotated(new cPoint(x,y-1));
						}
					}
					
				}
				break;
				case 3:
				if(checkWall(x,y+1) && checkFloor(x,y+2)){
					//pathFinder.setNewPath(new cPoint(x,y), new cPoint(x,y+2));
					pathFinder = new shortestPath(returnPathMap(),new cPoint(x,y), new cPoint(x,y+2),width,height);
					if(pathFinder.returnPath().size()<2){
						makeGenericFloor(new cPoint(x,y+1));
						if(buttonPuzzle){
							makeDoorRotated(new cPoint(x,y+1));
							//addDoor(new cPoint(x,y+1),addButton(new cPoint(x,y+1)));
						}
					}
					
				}
				break;
				}
				}
		}
	}
	public void addButton(cPoint door, cPoint button){
		buttons.add(new buttonClass(false,door,button));
	}
	private cPoint getEmptySpace(){
		randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height )); 
		while(returnAnyProperties(new cPoint(randomPoint.getX(),randomPoint.getY()))){
			randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height ));
		}
		return (randomPoint);
	}
	private cPoint getEmptySpace(cRect searchArea){
		randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height )); 
		while(returnAnyProperties(new cPoint(randomPoint.getX(),randomPoint.getY())) || !searchArea.inSquare(randomPoint)){
			randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height ));
		}
		return (randomPoint);
	}
	private cPoint getEmptySpaceExclusion(cRect searchArea){
		//System.out.println("ESpace" + width + " : " + height);
		randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height )); 
		while(returnAnyProperties(new cPoint(randomPoint.getX(),randomPoint.getY())) || searchArea.inSquare(randomPoint)){
			randomPoint = new cPoint(random.nextInt( width ),random.nextInt( height ));
		}
		return (randomPoint);
	}
	public void addDoor(cPoint door, cPoint button){
		doors.add(new doorClass(true,door,button));
	}
	public boolean getDoorClosed(cPoint location){
		for (doorClass dClass:doors){
			if(location.cEquals(dClass.getDoor())){
				return dClass.getButtonOn();
			}
		}
		return false;
	}
	public boolean getButtonOn(cPoint location){
		for (buttonClass bClass:buttons){
			if(location.cEquals(bClass.getButtonLocation())){
				return bClass.getButtonOn();
			}
		}
		return false;
		
	}
	public int getButton(cPoint location){
		for (i =0; i < buttons.size();i++){
			if(location.cEquals(buttons.get(i).getButtonLocation())){
				return i;
			}
		}
		return -1;
		
	}
	public int getDoor(cPoint location){
		for (i =0; i < buttons.size();i++){
			if(location.cEquals(doors.get(i).getDoor())){
				return i;
			}
		}
		return -1;
		
	}
	public buttonClass getButtonClass(int index){
		return buttons.get(index);
	}
	public void createTerrain(cPoint center, int radius){
		for(y = (int) ((center.getY()-radius)<0?0:(center.getY()-radius)); 
		y < ((center.getY()+radius)>height?height:(center.getY()+radius));y++){
			for(x=(int) ((center.getX()-radius)<0?0:(center.getX()-radius));
			x<((center.getX()+radius)>height?height:(center.getX()+radius));x++){
				randomPoint.setPoint(x, y);
				addHeight(new cPoint(x,y), ((randomPoint.getXDistance(center)>randomPoint.getYDistance(center)
						?randomPoint.getXDistance(center):randomPoint.getYDistance(center))-5) * .5f);
			}
		}
	}
	public cPoint getPlayer(){return playerStart;}
	//public void setPlayer(cPoint pos){playerStart= new cPoint(pos);}
	public int[][] getObstacleMap(){
		oMap = new int[width][height];
		for(y = 0; y < height;y++){
			for(x  =0 ;x< width;x++){
				oMap[x][y] = returnPassable(new cPoint(x,y))?1:0;
				if(returnPassable(new cPoint(x,y))){
					oMap[x][y] = !returnBox(new cPoint(x,y))?1:1000;
				}
			}
		}
		for (doorClass dClass: doors){
			if(dClass.getButtonOn()){
				oMap[(int) dClass.getDoor().getX()][(int) dClass.getDoor().getY()] = 0;
			}
		}
		return oMap;
	}
	//Map used for the solvable class
	public int[][] getSolvableMap(){
		oMap = new int[width][height];
		for(y = 0; y < height;y++){
			for(x  =0 ;x< width;x++){
				oMap[x][y] = returnPassable(new cPoint(x,y))?1:0;
				if(returnDoor(new cPoint(x,y))){
					oMap[x][y] = 2;
				}
			}
		}
		return oMap;
	}
	public int[][] getEnemyMap(){
		oMap = new int[width][height];
		for(y = 0; y < height;y++){
			for(x  =0 ;x< width;x++){
				oMap[x][y] = returnPassable(new cPoint(x,y))?1:0;
				if(returnPassable(new cPoint(x,y))){
					oMap[x][y] = !returnBox(new cPoint(x,y))?1:0;
				}
			}
		}
		for (doorClass dClass: doors){
			if(dClass.getButtonOn()){
				oMap[(int) dClass.getDoor().getX()][(int) dClass.getDoor().getY()] = 0;
			}
		}
		return oMap;
	}
	public int getIndex(){return this.index;}
	public cPoint getDimensions(){return new cPoint(width,height);}
	public Color getColor(){return this.color;}
	public cPoint getPuzzleExit(){
		return puzzleExit;
	}
	public int getDungeonType(){
		return dungeonType;
	}
	//This will do more later on
	public boolean trackPlayer(cPoint location){
		int position = getButton(location);
		//System.out.println(" p:" + position);
		if(!location.cEquals(playerLast)){
			playerLast = new cPoint(location);
			if(position!=-1){
				//for(doorClass door:doors){
				//	door.getDoor().printPoint();
				//}
				int doorPosition = getDoor(buttons.get(position).getDoor());
				if((buttons.get(position).getFlippedOnOff() || !buttons.get(position).getButtonOn()) && !buttons.get(position).getPressureSwitch()){
					buttons.get(position).switchButton();
					doors.get(doorPosition).switchButton();
					tHolder.switchTile(doors.get(doorPosition).getButtonLocation());
					tHolder.switchTile(doors.get(doorPosition).getDoor());
				}else if (buttons.get(position).getPressureSwitch()){
					if(buttons.get(position).getFlippedOnOff() || !buttons.get(position).getButtonOn()){
						buttons.get(position).switchButton();
						tHolder.switchTile(buttons.get(position).getButtonLocation());
						//buttons.get(position).getButtonLocation().printPoint();
					}
					if(doors.get(doorPosition).shouldSwitchButton(buttons) && doors.get(doorPosition).getButtonOn()){
						doors.get(doorPosition).switchButton();
						//System.out.println("All Switches On");
						tHolder.switchTile(doors.get(doorPosition).getDoor());
						//doors.get(doorPosition).getDoor().printPoint();
					}else if(!doors.get(doorPosition).getButtonOn()){
						//System.out.println("Button Turned Off");
						doors.get(doorPosition).switchButton();
						tHolder.switchTile(doors.get(doorPosition).getDoor());
					}
				}
				return true;
			}
		}
		
		return false;
	}
	public boolean tryingToMoveBox(cPoint playerLocation, cPoint boxLocation){
		//Player on top of box
		if(playerLocation.getY() > boxLocation.getY()){
			if(boxLocation.getY()-1 >= 0){
				if(!returnAnyProperties(new cPoint(boxLocation.getX(),boxLocation.getY()-1))){
					resetProperties(new cPoint(boxLocation.getX(),boxLocation.getY()));
					makeMovableBox(new cPoint(boxLocation.getX(),boxLocation.getY()-1));
					setTiles(false);
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
		}
		//Player under box
		else if(playerLocation.getY() < boxLocation.getY()){
			if(boxLocation.getY()+1 < height){
				if(!returnAnyProperties(new cPoint(boxLocation.getX(),boxLocation.getY()+1))){
					resetProperties(new cPoint(boxLocation.getX(),boxLocation.getY()));
					makeMovableBox(new cPoint(boxLocation.getX(),boxLocation.getY()+1));
					setTiles(false);
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
		}
		//Player left of box (unrotated. actually right)
		else if(playerLocation.getX() < boxLocation.getX()){
			if(boxLocation.getX()+1 < width){
				if(!returnAnyProperties(new cPoint(boxLocation.getX()+1,boxLocation.getY()))){
					resetProperties(new cPoint(boxLocation.getX(),boxLocation.getY()));
					makeMovableBox(new cPoint(boxLocation.getX()+1,boxLocation.getY()));
					setTiles(false);
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
		}
		//Player right of box
		else{
			if(boxLocation.getX()-1 >= 0){
				if(!returnAnyProperties(new cPoint(boxLocation.getX()-1,boxLocation.getY()))){
					resetProperties(new cPoint(boxLocation.getX(),boxLocation.getY()));
					makeMovableBox(new cPoint(boxLocation.getX()-1,boxLocation.getY()));
					setTiles(false);
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
		}
	}
	public boolean getPuzzle(){
		return isPuzzle;
	}
	public boolean testDoubleWall(cPoint position, cPoint direction){
		cPoint add = new cPoint(position.addPoints(direction)), sub = new cPoint(position.subPoints(direction));
		if(!checkWall(add.getX(), add.getY()) && !checkWall(sub.getX(), sub.getY())){
			return true;
		}
		return false;
	}
}

